package com.yang.spring.core.bean.builder;


import com.yang.spring.core.annotations.Qualifier;
import com.yang.spring.core.bean.BeanFactory;
import com.yang.spring.core.bean.definition.BeanDefinition;
import com.yang.spring.core.bean.enums.BeanDefinitionExtendsEnum;
import com.yang.spring.core.utils.CollectionUtils;
import com.yang.spring.core.utils.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;

public class BeanBeanBuilder extends AbstractBeanBuilder {
    @Override
    public Object buildBean(BeanDefinition beanDefinition) throws InstantiationException, IllegalAccessException, InvocationTargetException {
        List<BeanDefinition> dependencyBeanDefinitionList = beanDefinition.getDependencyBeanDefinitionList();
        if (CollectionUtils.isNotEmpty(dependencyBeanDefinitionList)) {
            // 构造依赖的bean
            for (BeanDefinition dependencyBeanDefinition : dependencyBeanDefinitionList) {
                Object dependencyInstance = BeanFactory.getBeanByName(dependencyBeanDefinition.getBeanName(), dependencyBeanDefinition.getBeanClassType());
                if (dependencyInstance == null) {
                    dependencyInstance = BeanFactory.buildBeanInstance(dependencyBeanDefinition);
                }
                dependencyBeanDefinition.setInstance(dependencyInstance);
            }
        }

        BeanDefinition configurationBeanDefinition = (BeanDefinition) beanDefinition.getExtend(BeanDefinitionExtendsEnum.CONFIGURATION_BEAN_DEFINITION.getValue());
        Method beanMethod = (Method) beanDefinition.getExtend(BeanDefinitionExtendsEnum.BEAN_METHOD.getValue());
        Class<?>[] parameterTypes = beanMethod.getParameterTypes();
        Parameter[] parameters = beanMethod.getParameters();

        Object instance = null;
        beanMethod.setAccessible(true);
        Object configurationInstance = configurationBeanDefinition.getInstance();

        if (parameterTypes.length == 0) {
            instance = beanMethod.invoke(configurationInstance);
        } else {
            Object[] parameterInstances = new Object[parameterTypes.length];
            for (int i = 0; i < parameterTypes.length; i++) {
                Class<?> parameterType = parameterTypes[i];
                Parameter parameter = parameters[i];
                BeanDefinition parameterBeanDefinition = new BeanDefinition();
                parameterBeanDefinition.setBeanClassType(parameterType);
                parameterBeanDefinition.setBeanName(parameter.getName());
                Qualifier qualifierAnnotation = parameter.getAnnotation(Qualifier.class);
                if (qualifierAnnotation != null && StringUtils.isNotEmpty(qualifierAnnotation.value())) {
                    parameterBeanDefinition.setBeanName(qualifierAnnotation.value());
                }
                Object parameterInstance = BeanFactory.getBeanByName(parameterBeanDefinition);
                if (parameterInstance != null) {
                    parameterInstances[i] = parameterInstance;
                } else {
                    parameterInstances[i] = BeanFactory.buildBeanInstance(parameterBeanDefinition);
                }
            }
            instance = beanMethod.invoke(configurationInstance, parameterInstances);
        }

        beanDefinition.setInstance(instance);
        richBeanDefinition(beanDefinition);
        BeanFactory.putBean(beanDefinition, instance);
        return instance;
    }
}
